#region Copyright (c) 2003-2004 ComponentGo!
/*
*********************************************************************
*                                                                   *
*       ComponentGo! Component Library                              *
*                                                                   *
*       Copyright (c) 2003-2004 ComponentGo!                        *
*       ALL RIGHTS RESERVED                                         *
*                                                                   *
*********************************************************************
*/
#endregion

using System;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Reflection;
using System.Windows.Forms;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;

namespace ComponentGo.Calendars {

	/// <summary>
	/// Represents a single appointment placed in a calendar.
	/// </summary>
	/// <remarks>
	/// An appointment can be an all-day appointment <see cref="AllDay"/> or take place at selected time.
	/// This class contains all the information needed to display an appointment's details
	/// in a calendar. Time when an appointment starts<see cref="DateBegin"/>, ends <see cref="DateEnd"/>
	/// and its description <see cref="Text"/> can be set.
	/// The layout of an appointment (colors, font) can also be set.
	/// </remarks>
	/// <example>
	/// The example shows how to add a new all-day appointment, planned for today and tomorrow.
	/// <code>
	/// DailyCalendar dailyCalendar = ...;
	/// Appointment ap = new Appointment(
	///		DateTime.Today, DateTime.Today.AddDays(1), true);
	/// ap.Text = "An appointment with friends in their village.";
	/// dailyCalendar.Appointments.Add(ap);
	/// </code>
	/// </example>
	[TypeConverter(typeof(Appointment.Converter))]
	[DesignTimeVisible(false)]
	[System.Runtime.InteropServices.ComVisible(true)]
	public class Appointment : ICloneable {

		#region Converter

		/// <summary>
		/// A class supporting edits of an appointment in a Visual Studio environment.
		/// </summary>
		internal class Converter : ExpandableObjectConverter 
		{

			/// <summary>
			/// Determines a possibility of converting an appointment to an object <c>InstanceDescriptor</c>.
			/// </summary>
			/// <param name="ctx">Conversion context.</param>
			/// <param name="t">A type a conversion can be performed to.</param>
			/// <returns>Returns <c>true</c> if <paramref name="t"/> is an <c>InstanceDescriptor</c>.</returns>
			public override bool CanConvertTo(ITypeDescriptorContext ctx, Type t) {
				if (t==typeof(InstanceDescriptor)) return true;
				return base.CanConvertTo(ctx, t);
			}

			static readonly Type [] constPars0 = new Type[] {
				typeof(DateTime), typeof(DateTime), typeof(bool), typeof(string), typeof(int), 
				typeof(int), typeof(Color),
				typeof(Color), typeof(Color), typeof(Color), typeof(Font),
				typeof(bool), typeof(AppTerminator), typeof(AppTerminator)};
			static readonly Type [] constPars1 = new Type[] {
				typeof(DateTime), typeof(DateTime), typeof(bool), typeof(string), typeof(int),
				typeof(int), typeof(Color),
				typeof(Color), typeof(Color), typeof(Color), typeof(Font) };
			static readonly Type [] constPars2 = new Type[] {
				typeof(DateTime), typeof(DateTime), typeof(bool), typeof(string), typeof(int) };


			/// <summary>
			/// Converts an appointment to an object <c>InstanceDescriptor</c>. 
			/// </summary>
			/// <param name="context">Conversion context.</param>
			/// <param name="culture">Conversion language.</param>
			/// <param name="value">Converted object of type <see cref="Appointment"/>.</param>
			/// <param name="destinationType">A type a conversion is to be performed to.</param>
			/// <returns>Converted object of type <c>InstanceDescriptor</c>.</returns>
			public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
				if (destinationType==typeof(InstanceDescriptor)) {
					Appointment ap = (Appointment)value;
					Type [] types;
					object [] pars;
					if (ap.LinkWithNext || ap.BeginTerminator!=AppTerminator.Standard || ap.EndTerminator!=AppTerminator.Standard) {
						types = constPars0;
						pars = new object[] { ap.DateBegin, ap.DateEnd, ap.AllDay, ap.Text, ap.ResourceIndex, 
												ap.Progress, ap.ProgressColor,
												ap.BusyColor, ap.BackColor, ap.ForeColor, ap.Font,
												ap.LinkWithNext, ap.BeginTerminator, ap.EndTerminator};
					}
					else if (ap.BusyColor==Color.Empty && ap.BackColor==Color.Empty && ap.ForeColor==Color.Empty && ap.Font==null) {
						types = constPars2;
						pars = new object[] { ap.DateBegin, ap.DateEnd, ap.AllDay, ap.Text, ap.ResourceIndex };
					}
					else {
						types = constPars1;
						pars = new object[] { ap.DateBegin, ap.DateEnd, ap.AllDay, ap.Text, ap.ResourceIndex, 
										ap.Progress, ap.ProgressColor,
										ap.BusyColor, ap.BackColor, ap.ForeColor, ap.Font };
					}

					ConstructorInfo ci = typeof(Appointment).GetConstructor(types);
					return new InstanceDescriptor(ci, pars);
				}

				return base.ConvertTo(context, culture, value, destinationType);
			}

		}

		#endregion

		#region General

		internal AppointmentCollection coll = null;

		/// <summary>
		/// Contructs a new appointment object.
		/// </summary>
		/// <remarks>
		/// An 'appointment time' period is not set and requires setting properties
		/// <see cref="DateBegin"/> and <see cref="DateEnd"/>. Otherwise an appointment 
		/// will not be visible in a calendar.
		/// </remarks>
		public Appointment() {
		}

		/// <summary>
		/// Contructs a new appointment object ant sets basic properties needed for 
		/// displaying an appointment in a calendar.
		/// </summary>
		/// <param name="dateBegin">appointment start time and date. Property <see cref="DateBegin"/>.</param>
		/// <param name="dateEnd">appointment finish time and date. Property <see cref="DateEnd"/>.</param>
		/// <param name="allDay">Determines, whether an appointment is an all-dy appointment. 
		///		Only a date of the appointment is meaningful then. Property <see cref="AllDay"/>.</param>
		///	<param name="resourceIndex">appointment is containded by resource with this index in 
		///		<see cref="RootCalendar.Resources"/> collection. Property <see cref="ResourceIndex"/>.</param>
		///	<remarks>
		///	If an appointment is an all-day appointment  <c>allDay==true</c>, <paramref name="dateBegin"/>
		///	is a date of the first day of an appointment, and <paramref name="dateEnd"/> a date
		///	of the last day.<para/>
		///	If an appointment is not an all-day appointment <c>allDay==false</c>, then <paramref name="dateBegin"/>
		///	sets the date and time an appointment begins and <paramref name="dateEnd"/> 
		///	a date and time an appointment ends. <paramref name="dateBegin"/> belongs to a period while
		///	<paramref name="dateEnd"/> does not.
		///	</remarks>
		public Appointment(DateTime dateBegin, DateTime dateEnd, bool allDay, int resourceIndex) {
			this.dateBegin = dateBegin;
			this.dateEnd = dateEnd;
			this.allDay = allDay;
			this.resourceIndex = resourceIndex;
		}

		/// <summary>
		/// Contructs a new appointment object ant sets basic properties needed for 
		/// displaying an appointment in a calendar.
		/// </summary>
		/// <param name="dateBegin">appointment start time and date. Property <see cref="DateBegin"/>.</param>
		/// <param name="dateEnd">appointment finish time and date. Property <see cref="DateEnd"/>.</param>
		/// <param name="allDay">Determines, whether an appointment is an all-dy appointment. 
		///		Only a date of the appointment is meaningful then. Property <see cref="AllDay"/>.</param>
		///	<remarks>
		///	If an appointment is an all-day appointment  <c>allDay==true</c>, <paramref name="dateBegin"/>
		///	is a date of the first day of an appointment, and <paramref name="dateEnd"/> a date
		///	of the last day.<para/>
		///	If an appointment is not an all-day appointment <c>allDay==false</c>, then <paramref name="dateBegin"/>
		///	sets the date and time an appointment begins and <paramref name="dateEnd"/> 
		///	a date and time an appointment ends. <paramref name="dateBegin"/> belongs to a period while
		///	<paramref name="dateEnd"/> does not.<para/>
		///	An Appointment is initialized with ResourceIndex set to 0.
		///	</remarks>
		public Appointment(DateTime dateBegin, DateTime dateEnd, bool allDay) : this(dateBegin, dateEnd, allDay, 0) {
		}

		/// <summary>
		/// Contructs a new appointment object ant sets basic properties needed for 
		/// displaying an appointment in a calendar.
		/// </summary>
		/// <param name="dateBegin">Appointment start time and date. Property <see cref="DateBegin"/>.</param>
		/// <param name="dateEnd">Appointment finish time and date. Property <see cref="DateEnd"/>.</param>
		/// <param name="allDay">Determines, whether an appointment is an all-dy appointment. 
		///		Only a date of the appointment is meaningful then. Property <see cref="AllDay"/>.</param>
		///	<param name="appText">Textual description of an appointment displayed in a calendar.</param>
		///	<param name="resourceIndex">appointment is containded by resource with this index in 
		///		<see cref="RootCalendar.Resources"/> collection. Property <see cref="ResourceIndex"/>.</param>
		///	<remarks>
		///	If an appointment is an all-day appointment  <c>allDay==true</c>, <paramref name="dateBegin"/>
		///	is a date of the first day of an appointment, and <paramref name="dateEnd"/> a date
		///	of the last day.<para/>
		///	If an appointment is not an all-day appointment <c>allDay==false</c>, then <paramref name="dateBegin"/>
		///	sets the date and time an appointment begins and <paramref name="dateEnd"/> 
		///	a date and time an appointment ends. <paramref name="dateBegin"/> belongs to a period while
		///	<paramref name="dateEnd"/> does not.
		///	</remarks>
		public Appointment(DateTime dateBegin, DateTime dateEnd, bool allDay, string appText, int resourceIndex)
			: this(dateBegin, dateEnd, allDay, resourceIndex) {
			this.text = appText;
		}

		/// <summary>
		/// Contructs a new appointment object ant sets basic properties needed for 
		/// displaying an appointment in a calendar.
		/// </summary>
		/// <param name="dateBegin">Appointment start time and date. Property <see cref="DateBegin"/>.</param>
		/// <param name="dateEnd">Appointment finish time and date. Property <see cref="DateEnd"/>.</param>
		/// <param name="allDay">Determines, whether an appointment is an all-dy appointment. 
		///		Only a date of the appointment is meaningful then. Property <see cref="AllDay"/>.</param>
		///	<param name="appText">Textual description of an appointment displayed in a calendar.</param>
		///	<param name="resourceIndex">appointment is containded by resource with this index in 
		///		<see cref="RootCalendar.Resources"/> collection. Property <see cref="ResourceIndex"/>.</param>
		///	<param name="linkWithNext">Determines whether an appointment is linked to a next one. 
		///		Property <see cref="LinkWithNext"/>.</param>
		///	<remarks>
		///	If an appointment is an all-day appointment  <c>allDay==true</c>, <paramref name="dateBegin"/>
		///	is a date of the first day of an appointment, and <paramref name="dateEnd"/> a date
		///	of the last day.<para/>
		///	If an appointment is not an all-day appointment <c>allDay==false</c>, then <paramref name="dateBegin"/>
		///	sets the date and time an appointment begins and <paramref name="dateEnd"/> 
		///	a date and time an appointment ends. <paramref name="dateBegin"/> belongs to a period while
		///	<paramref name="dateEnd"/> does not.
		///	</remarks>
		public Appointment(DateTime dateBegin, DateTime dateEnd, bool allDay, string appText, int resourceIndex, bool linkWithNext)
			: this(dateBegin, dateEnd, allDay, appText, resourceIndex) {
			this.linkWithNext = linkWithNext;
		}

		/// <summary>
		/// Contructs a new appointment object ant sets basic properties needed for 
		/// displaying an appointment in a calendar.
		/// </summary>
		/// <param name="dateBegin">Appointment start time and date. Property <see cref="DateBegin"/>.</param>
		/// <param name="dateEnd">Appointment finish time and date. Property <see cref="DateEnd"/>.</param>
		/// <param name="allDay">Determines, whether an appointment is an all-day appointment. 
		///		Only a date of an appointment is meaningful then. Property <see cref="AllDay"/>.</param>
		///	<param name="appText">Text description of an appointment displayed on a calendar.
		///		Property <see cref="Text"/>.</param>
		///	<param name="busyColor">Color of a 'busy' marker 
		///	 located on the left side of the appointment. Property <see cref="BusyColor"/>.</param>
		///	<param name="backColor"> Color of a rectangle, an appointment is displayed in. 
		///		Property <see cref="BackColor"/>.</param>
		///	<param name="foreColor">Color of a font used to display an appointment's description.
		///		Property <see cref="ForeColor"/>.</param>
		///	<param name="font">>A font used to display an appointment's description.
		///		Property <see cref="Font"/>.</param>
		///	<param name="resourceIndex">appointment is containded by resource with this index in 
		///		<see cref="RootCalendar.Resources"/> collection. Property <see cref="ResourceIndex"/>.</param>
		///	<param name="progress">A value of a <see cref="Progress"/> property denotes a degree of completion of a task.</param>
		///	<param name="progressColor">Color of a progress bar. Property <see cref="ProgressColor"/>.</param>
		///	<remarks>
		///	If an appointment is not an all-day appointment <c>allDay==false</c>, <paramref name="dateBegin"/>
		///	denotes a date and time an appointment starts, and  <paramref name="dateEnd"/> 
		///	denotes a date and time an appointment ends.  <paramref name="dateBegin"/> belongs to a period while
		///	<paramref name="dateEnd"/> does not.
		///	</remarks>
		public Appointment(DateTime dateBegin, DateTime dateEnd, bool allDay, string appText, int resourceIndex, int progress, Color progressColor, Color busyColor, Color backColor, Color foreColor, Font font)
			: this(dateBegin, dateEnd, allDay, appText, resourceIndex) {
			this.busyColor = busyColor;
			this.backColor = backColor;
			this.foreColor = foreColor;
			this.font = font;
			this.progress = progress;
			this.progressColor = progressColor;
		}

		/// <summary>
		/// Contructs a new appointment object ant sets basic properties needed for 
		/// displaying an appointment in a calendar.
		/// </summary>
		/// <param name="dateBegin">Appointment start time and date. Property <see cref="DateBegin"/>.</param>
		/// <param name="dateEnd">Appointment finish time and date. Property <see cref="DateEnd"/>.</param>
		/// <param name="allDay">Determines, whether an appointment is an all-day appointment. 
		///		Only a date of an appointment is meaningful then. Property <see cref="AllDay"/>.</param>
		///	<param name="appText">Text description of an appointment displayed on a calendar.
		///		Property <see cref="Text"/>.</param>
		///	<param name="busyColor">Color of a 'busy' marker 
		///	 located on the left side of the appointment. Property <see cref="BusyColor"/>.</param>
		///	<param name="backColor"> Color of a rectangle, an appointment is displayed in. 
		///		Property <see cref="BackColor"/>.</param>
		///	<param name="foreColor">Color of a font used to display an appointment's description.
		///		Property <see cref="ForeColor"/>.</param>
		///	<param name="font">>A font used to display an appointment's description.
		///		Property <see cref="Font"/>.</param>
		///	<param name="progress">The value of a <see cref="Progress"/> property determines a degree of task implementation.</param>
		///	<param name="progressColor">Color of a progress bar. Property <see cref="ProgressColor"/>.</param>
		///	<remarks>
		///	If an appointment is not an all-day appointment <c>allDay==false</c>, <paramref name="dateBegin"/>
		///	denotes a date and time an appointment starts, and  <paramref name="dateEnd"/> 
		///	denotes a date and time an appointment ends.  <paramref name="dateBegin"/> belongs to a period while
		///	<paramref name="dateEnd"/> does not.<para/>
		///	An Appointment is initialized with ResourceIndex set to 0.
		///	</remarks>
		public Appointment(DateTime dateBegin, DateTime dateEnd, bool allDay, string appText, int progress, Color progressColor, Color busyColor, Color backColor, Color foreColor, Font font)
			: this(dateBegin, dateEnd, allDay, appText, 0, progress, progressColor, busyColor, backColor, foreColor, font) {
		}

		/// <summary>
		/// Contructs a new appointment object ant sets basic properties needed for 
		/// displaying an appointment in a calendar.
		/// </summary>
		/// <param name="dateBegin">Appointment start time and date. Property <see cref="DateBegin"/>.</param>
		/// <param name="dateEnd">Appointment finish time and date. Property <see cref="DateEnd"/>.</param>
		/// <param name="allDay">Determines, whether an appointment is an all-day appointment. 
		///		Only a date of an appointment is meaningful then. Property <see cref="AllDay"/>.</param>
		///	<param name="appText">Text description of an appointment displayed on a calendar.
		///		Property <see cref="Text"/>.</param>
		///	<param name="resourceIndex">appointment is containded by resource with this index in 
		///		<see cref="RootCalendar.Resources"/> collection. Property <see cref="ResourceIndex"/>.</param>
		///	<param name="progress">A value of a <see cref="Progress"/> property denotes a degree of completion of a task.</param>
		///	<param name="progressColor">Color of a progress bar. Property <see cref="ProgressColor"/>.</param>
		///	<param name="busyColor">Color of a 'busy' marker 
		///	 located on the left side of the appointment. Property <see cref="BusyColor"/>.</param>
		///	<param name="backColor"> Color of a rectangle, an appointment is displayed in. 
		///		Property <see cref="BackColor"/>.</param>
		///	<param name="foreColor">Color of a font used to display an appointment's description.
		///		Property <see cref="ForeColor"/>.</param>
		///	<param name="font">>A font used to display an appointment's description.
		///		Property <see cref="Font"/>.</param>
		///	<param name="beginTerm">Determines the shape of an appointment's beginning.  
		///		Property <see cref="BeginTerminator"/>.</param>
		///	<param name="endTerm">Determines the shape of an appointment's end.  
		///		Property <see cref="EndTerminator"/>.</param>
		///	<param name="linkWithNext">Determines whether an appointment is linked to a next one. 
		///		Property <see cref="LinkWithNext"/>.</param>
		///	<remarks>
		///	If an appointment is not an all-day appointment <c>allDay==false</c>, <paramref name="dateBegin"/>
		///	denotes a date and time an appointment starts, and  <paramref name="dateEnd"/> 
		///	denotes a date and time an appointment ends.  <paramref name="dateBegin"/> belongs to a period while
		///	<paramref name="dateEnd"/> does not.
		///	</remarks>
		public Appointment(DateTime dateBegin, DateTime dateEnd, bool allDay, string appText, int resourceIndex,
			int progress, Color progressColor,
			Color busyColor, Color backColor, Color foreColor, Font font,
			bool linkWithNext, AppTerminator beginTerm, AppTerminator endTerm)
			: this(dateBegin, dateEnd, allDay, appText, resourceIndex, progress, progressColor, busyColor, backColor, foreColor, font) {
			this.linkWithNext = linkWithNext;
			this.beginTerminator = beginTerm;
			this.endTerminator = endTerm;
		}

		/// <summary>
		/// Returns a textual representation of an appointment.
		/// </summary>
		/// <param name="provider">An <see cref="IFormatProvider"/> that supplies culture-specific formatting information.</param>
		/// <returns>Textual representation of an appointment.</returns>
		/// <remarks>
		/// A string consisting of a date an appointment starts <see cref="DateBegin"/> 
		/// and a textual description of an appointment <see cref="Text"/>.
		/// </remarks>
		public string ToString(IFormatProvider provider) {
			if (AllDay)
				return string.Format(provider, "{0:d}: {1}", DateBegin, Text);
			return string.Format(provider, "{0}: {1}", DateBegin, Text);
		}

		/// <summary>
		/// Returns a textual representation of an appointment.
		/// </summary>
		/// <returns>Textual representation of an appointment.</returns>
		/// <remarks>
		/// A string consisting of a date an appointment starts <see cref="DateBegin"/> 
		/// and a textual description of an appointment <see cref="Text"/>.
		/// </remarks>
		public override string ToString() {
			return ToString(null);
		}

		/// <summary> 
		/// Field representing an empty array of appointment objects. 
		/// </summary> 
		public static readonly Appointment [] EmptyArray = new Appointment[0];

		#endregion

		#region Properties

		#region Text

		string text = "";

		/// <summary>
		/// Textual description of an appointment displayed in a calendar.
		/// </summary>
		[Category("Data")]
		[Description("Textual description of an appointment displayed in a calendar.")]
		[DefaultValue("")]
		public string Text {
			get { return text; }
			set {
				if (text==value) return;
				text = value;
				change(false);
			}
		}

		#endregion

		#region DateTime

		DateTime dateBegin = DateTime.MinValue;

		/// <summary>
		/// Date and/or time an appointment starts.
		/// </summary>
		///	<remarks>
		///	If an appointment is an all-day appointment  <c>allDay==true</c>, this parameter
		///	is a date of the first day of an appointment.<para/>
		///	If an appointment is not an all-day appointment <c>allDay==false</c>, this parameter
		///	sets the date and time an appointment begins and <paramref name="dateEnd"/> 
		///	a date and time an appointment ends. <paramref name="dateBegin"/> belongs to a period while
		///	<paramref name="dateEnd"/> does not.
		///	<seealso cref="AllDay"/>
		///	<seealso cref="DateEnd"/>
		///	</remarks>
		[Category("Data")]
		[Description("Date and/or time an appointment starts.")]
		public DateTime DateBegin {
			get { return dateBegin; }
			set {
				if (dateBegin==value) return;
				dateBegin = value;
				change(true);
			}
		}

		DateTime dateEnd = DateTime.MinValue;

		/// <summary>
		/// Date and/or time an appointment ends.
		/// </summary>
		///	<remarks>
		///	If an appointment is an all-day appointment  <c>allDay==true</c>, this parameter
		///	is a date of the last day of an appointment.<para/>
		///	If an appointment is not an all-day appointment <c>allDay==false</c>, this parameter
		///	sets the date and time an appointment ends. <paramref name="dateBegin"/> belongs to a period while
		///	<seealso cref="AllDay"/>
		///	<seealso cref="DateBegin"/>
		///	</remarks>
		[Category("Data")]
		[Description("Date and/or time an appointment ends.")]
		public DateTime DateEnd {
			get { return dateEnd; }
			set {
				if (dateEnd==value) return;
				dateEnd = value;
				change(true);
			}
		}

		bool allDay = false;

		/// <summary>
		/// Determines, whether an appointment is an all-day appointment.
		/// </summary>
		/// <remarks>
		/// A value of <c>true</c> denotes an all-day appointment.
		/// A value of <c>false</c> value denotes an appointment that is not an all-day appointment.
		/// </remarks>
		///	<seealso cref="DateBegin"/>
		///	<seealso cref="DateEnd"/>
		[Category("Data")]
		[Description("A value of 'true' denotes an all-day appointmen. A value of 'false' denotes an appointment that is not an all-day appointment.")]
		[DefaultValue(false)]
		public bool AllDay {
			get { return allDay; }
			set {
				if (allDay==value) return;
				allDay = value;
				change(true);
			}
		}

		#endregion

		#region LinkWith & Resource

		bool linkWithNext = false;

		/// <summary>
		/// Determines whether an appointment is linked to the next appointment in a collection.
		/// </summary>
		/// <remarks>
		/// Appointment is linked to the next one only when this property has a value of <b>true</b> 
		/// and its end <see cref="DateEnd"/> is adjacent to the beginning  <see cref="DateBegin"/> 
		/// of the next one.<para/>
		/// Concerns a <see cref="ResourceScheduler"/> control only.
		/// </remarks>
		///	<seealso cref="NextLinked"/>
		///	<seealso cref="PreviousLinked"/>
		[Category("Data")]
		[Description("Determines whether an appointment is linked to the next appointment in a collection.")]
		[DefaultValue(false)]
		public bool LinkWithNext {
			get { return linkWithNext; }
			set {
				if (linkWithNext==value) return;
				linkWithNext = value;
				change(true);
			}
		}

		int resourceIndex = 0;

		/// <summary>
		/// Index of a resource appointment is assigned to.
		/// </summary>
		[Category("Data")]
		[Description("Index of a resource appointment is assigned to.")]
		[DefaultValue(0)]
		public int ResourceIndex {
			get { return resourceIndex; }
			set {
				if (resourceIndex==value) return;
				resourceIndex = value;
				change(true);
			}
		}

		#endregion

		#region Colors & Font

		Color backColor = Color.Empty;

		/// <summary>
		/// Background color of a rectangle an appointment is displayed in.
		/// <seealso cref="ForeColor"/>
		/// </summary>
		[Category("Appearance")]
		[Description("Background color of a rectangle an appointment is displayed in.")]
		public Color BackColor {
			get { return backColor; }
			set {
				if (backColor==value) return;
				backColor = value;
				change(false);
			}
		}

		internal Color GetBackColor() {
			return BackColor!=Color.Empty || coll.calendar==null 
				? BackColor : coll.calendar.BackColor;
		}

		internal Color GetPrintBackColor() 
		{
			return coll.calendar.BackColor;
		}

		Color lineColor = Color.Empty;

		/// <summary>
		/// Color of rectangle bounds an appointment is displayed in.
		/// <seealso cref="ForeColor"/>
		/// </summary>
		[Category("Appearance")]
		[Description("Color of rectangle bounds an appointment is displayed in.")]
		public Color LineColor 
		{
			get { return lineColor; }
			set 
			{
				if (lineColor==value) return;
				lineColor = value;
				change(false);
			}
		}

		internal Color GetLineColor() 
		{
			return LineColor!=Color.Empty || coll.calendar==null 
				? LineColor : coll.calendar.LineColor;
		}


		
		Color foreColor = Color.Empty;

		/// <summary>
		/// A color of a font an appointment is displayed with.
		/// <seealso cref="BackColor"/>
		/// <seealso cref="Font"/>
		/// </summary>
		[Category("Appearance")]
		[Description("A color of a font an appointment is displayed with.")]
		public Color ForeColor {
			get { return foreColor; }
			set {
				if (foreColor==value) return;
				foreColor = value;
				change(false);
			}
		}

		internal Color GetForeColor() {
			return ForeColor!=Color.Empty || coll.calendar==null 
				? ForeColor : coll.calendar.ForeColor;
		}

		internal Color GetPrintForeColor() 
		{
			return coll.calendar.ForeColor;
		}

		Font font = null;

		/// <summary>
		/// A font an appointment is displayed with.
		/// <seealso cref="ForeColor"/>
		/// </summary>
		[DefaultValue(null)]
		[Category("Appearance")]
		[Description("A font an appointment is displayed with.")]
		public Font Font {
			get { return font; }
			set {
				if (font==value) return;
				font = value;
				change(false);
			}
		}

		Color busyColor = Color.Empty;

		/// <summary>
		///	Color of a 'busy' marker 
		///	 located on the left side of the appointment. Property <see cref="BusyColor"/>.
		/// </summary>
		/// <remarks>
		/// If an appointment is not an all-day appointment, a marker is displayed as a vertical bar
		/// attached to a left side of a day's rectangle. Ifan appointment is an all-day appointment, 
		/// a vertical bar alongside the times, is marked with this color, 
		/// provided no all-day appointment is scheduled at the same time.<para/>
		/// Property used only in a <see cref="DailyCalendar"/> control.
		/// </remarks>
		[Category("Appearance")]
		[Description("Color of a 'busy' marker located on the left side of the appointment.")]
		public Color BusyColor {
			get { return busyColor; }
			set {
				if (busyColor==value) return;
				busyColor = value;
				change(false);
			}
		}

		Color progressColor = SystemColors.ScrollBar;

		/// <summary>
		/// A color of a progress bar an appointment is displayed with.
		/// <seealso cref="Progress"/>
		/// </summary>
		[Category("Appearance")]
		[Description("A color of a progress bar an appointment is displayed with.")]
		public Color ProgressColor {
			get { return progressColor; }
			set {
				if (progressColor==value) return;
				progressColor = value;
				change(false);
			}
		}

		#endregion

		#region Selected

		bool selected = false;

		/// <summary>
		/// Determines whether an appointment is selected.
		/// </summary>
		/// <remarks>
		/// If an appointment is selected, the background of its rectangle on a calendar  
		/// is marked with a <see cref="BaseCalendar.SelectedColor"/> color.
		/// </remarks>
		[Browsable(false)]
		public bool Selected {
			get { return selected; }
			set {
				if (selected==value) return;
				selected = value;
				change(false);
				if (coll.calendar!=null)
					coll.calendar.OnSelectionChanged(new AppointmentEventArgs(this));
			}
		}

		#endregion

		#region Terminator & Progress

		AppTerminator beginTerminator = AppTerminator.Standard;

		/// <summary>
		/// Determines a shape of the beginning of a rectangle representing an appointment.
		/// </summary>
		/// <remarks>
		/// Concerns a  <see cref="ResourceScheduler"/>. control only.
		/// </remarks>
		[Category("Appearance")]
		[Description("Determines a shape of the beginning of a rectangle representing an appointment.")]
		public AppTerminator BeginTerminator {
			get { return beginTerminator; }
			set {
				if (beginTerminator==value) return;
				beginTerminator = value;
				change(false);
			}
		}

		AppTerminator endTerminator = AppTerminator.Standard;

		/// <summary>
		/// Determines a shape of the end of a rectangle representing an appointment.
		/// </summary>
		/// <remarks>
		/// Concerns a  <see cref="ResourceScheduler"/>. control only..
		/// </remarks>
		[Category("Appearance")]
		[Description("Determines a shape of the end of a rectangle representing an appointment.")]
		public AppTerminator EndTerminator {
			get { return endTerminator; }
			set {
				if (endTerminator==value) return;
				endTerminator = value;
				change(false);
			}
		}

		int progress = 0;

		/// <summary>
		/// Determines a degree of implementation of an appointment.
		/// </summary>
		/// <remarks>
		/// A control displays a degree of implementation as a progressbar.<para/>
		/// Property has a range of values from 0 to 100.
		/// </remarks>
		[Category("Data")]
		[Description("Determines a degree of implementation of an appointment.")]
		[DefaultValue(0)]
		public int Progress {
			get { return progress; }
			set {
				if (progress==value) return;
				if (!(0<=value && value<=100))
					throw new ArgumentOutOfRangeException("value", value, "Allow values from 0 to 100");
				progress = value;
				change(false);
			}
		}

		#endregion

		#region Tag

		object tag = null;

		/// <summary>
		/// Gets or sets an object that contains data to associate with the appointment.
		/// </summary>
		/// <value>
		/// An object that contains information that is associated with the appointment.
		/// </value>
		/// <remarks>
		/// The <b>Tag</b> property can be used to store any object that you want 
		/// to associate with an appointment. Although you can store any item, 
		/// the <b>Tag</b> property is typically used to store string information about 
		/// the item such as a unique identifier or the index position of the 
		/// item's data in a database.
		/// </remarks>
		[Browsable(false)]
		public object Tag {
			get { return tag; }
			set { tag = value; }
		}

		#endregion

		#endregion

		#region Notification

		void change(bool recalc) {
			if (coll!=null && coll.calendar!=null)
				coll.calendar.Resync(recalc);
		}

		#endregion

		#region Implementation

		internal DateTime dateStart {
			get {
				if (AllDay)
					return DateBegin.Date;
				return DateBegin;
			}
		}

		internal DateTime dateStop {
			get {
				if (AllDay)
					return DateEnd.Date.AddDays(1);
				return DateEnd;
			}
		}

		/// <summary>
		/// Determines the next linked appointment in a collection.
		/// </summary>
		/// <remarks>
		/// Appointment is linked to the next one only when a <see cref="LinkWithNext"/> property 
		/// has a value of <b>true</b> and its end <see cref="DateEnd"/> adjoins the beginning 
		/// <see cref="DateBegin"/> of the next one.
		/// <para/>
		/// Returns <b>null</b> if the appointment is not linked to the next one, or if 
		/// an appointment was not added to any collection.<para/>
		/// Concerns a <see cref="ResourceScheduler"/> control only.
		/// <seealso cref="PreviousLinked"/>
		/// </remarks>
		[Browsable(false)]
		public Appointment NextLinked {
			get {
				if (!LinkWithNext || coll==null) return null;
				int idx = coll.IndexOf(this);
				if (0<=idx && idx<coll.Count-1 && dateStop==coll[idx+1].dateStart) 
					return coll[idx+1];
				return null;
			}
		}

		/// <summary>
		/// Determines the previous linked appointment in a collection.
		/// </summary>
		/// <remarks>
		/// Appointment is linked to the next one only when a <see cref="LinkWithNext"/> property 
		/// has a value of <b>true</b> and its end <see cref="DateEnd"/> adjoins the beginning 
		/// <see cref="DateBegin"/> of the next one.<para/>
		/// Returns <b>null</b> if the appointment is not linked to the next one or if an appointment 
		/// was not added to any collection.<para/>
		/// Concerns a <see cref="ResourceScheduler"/> control only.
		/// <seealso cref="PreviousLinked"/>
		/// </remarks>
		[Browsable(false)]
		public Appointment PreviousLinked {
			get {
				if (coll==null) return null;
				int idx = coll.IndexOf(this);
				if (idx>0 && dateStart==coll[idx-1].dateStop && coll[idx-1].LinkWithNext)
					return coll[idx-1];
				return null;
			}
		}

		/// <summary>
		/// Returns an array of all linked objects <see cref="Appointment"/>.
		/// </summary>
		/// <remarks>
		/// Returned objects are linked indirectly or directly with this object <see cref="Appointment"/>.
		/// If no object is linked, a one element array <c>{ this }</c> is returned.
		/// </remarks>
		[Browsable(false)]
		public Appointment [] Linked {
			get {
				if (coll==null)
					return new Appointment[] {this};

				int idx = coll.IndexOf(this);
				
				int start = idx;
				while (start>0 && coll[start-1].dateStop==coll[start].dateStart && coll[start-1].LinkWithNext)
					--start;
				
				int stop = idx;
				while (stop<coll.Count-1 && coll[stop+1].dateStart==coll[stop].dateStop && coll[stop].LinkWithNext)
					++stop;

				Appointment [] arr = new Appointment[stop-start+1];
				for (int i = 0; i<arr.Length; ++i)
					arr[i] = coll[start+i];
				return arr;
			}
		}

		internal bool isGhost = false;

		/// <summary>
		/// Determines whether an appointment is displayed as semitransparent.
		/// </summary>
		/// <remarks>
		/// An appointment is displayed as semitransparent when it is in a forbidden 
		/// place during a drag&amp;drop operation.
		/// </remarks>
		[Browsable(false)]
		public bool IsGhost {
			get {
				return isGhost;
			}
		}

		#endregion

		#region Implementation of IComparable

		/// <summary>
		/// Compares times of two appointments.
		/// </summary>
		/// <param name="ap">Appointment object compared to the current appointment.</param>
		/// <returns>-1, 0 or 1 if an appointment is repectively less than, equal to or greater than the compared one.
		/// </returns>
		///	<remarks>
		///	<see cref="DateBegin"/> is compared first, then
		///	<see cref="DateEnd"/> and a  <see cref="Text"/> in the end.
		///	</remarks>
		public int CompareTo(Appointment ap) {
			int i = DateBegin.CompareTo(ap.DateBegin);
			if (i!=0) return i;
			i = DateEnd.CompareTo(ap.DateEnd);
			if (i!=0) return i;
			return Text.CompareTo(ap.Text);
		}

		#endregion

		#region Implementation of ICloneable

		object ICloneable.Clone() {
			return Clone();
		}

		/// <summary>
		/// Creates a copy of an appointment object.
		/// </summary>
		/// <returns>Another appointment object being a copy of a current one.</returns>
		/// <remarks>
		/// If you inherit from a class <see cref="Appointment"/> you should also
		/// override this method, as it is used by a drag&amp;drop operations
		/// </remarks>
		public virtual Appointment Clone() {
			Appointment app = (Appointment)MemberwiseClone();
			app.coll = null;
			return app;
		}

		#endregion

		#region Operations

		/// <summary>
		/// Forces a calendar to display an appointment if it is not visible.
		/// </summary>
		public void EnsureVisible() {
			if (coll.calendar==null)
				throw new InvalidOperationException();
			coll.calendar.EnsureVisible(dateStart, dateStop, ResourceIndex);
		}

		/// <summary>
		/// Forces a start of an appointment edit.
		/// </summary>
		/// <remarks>
		/// To edit an appointment an <see cref="Text"/> editor control for a property being edited 
		/// is opened in an appointment's rectangle.
		/// </remarks>
		public void Edit() {
			if (coll.calendar==null)
				throw new InvalidOperationException();
			coll.calendar.Appointments.UnselectAll();
			Selected = true;
			coll.calendar.startEdit(this);
		}

		/// <summary>
		/// This method assigns a set of date and time properties of an appointment, 
		/// moving it on a calendar control when needed.
		/// </summary>
		/// <param name="dateBegin">Date and/or time an appointment starts.</param>
		/// <param name="dateEnd">Date and/or time an appointment ends.</param>
		/// <param name="allDay">Determines, whether an appointment is an all-day appointment.</param>
		///	<seealso cref="DateBegin"/>
		///	<seealso cref="DateEnd"/>
		///	<seealso cref="AllDay"/>
		public void Move(DateTime dateBegin, DateTime dateEnd, bool allDay) {
			if (dateBegin==DateBegin && dateEnd==DateEnd && allDay==AllDay)
				return;
			this.dateBegin = dateBegin;
			this.dateEnd = dateEnd;
			this.allDay = allDay;
			change(true);
		}

		#endregion
	}

	public class AppointmentBindingEventArgs : EventArgs
	{
		public Object source;
		public Appointment app;

		public AppointmentBindingEventArgs(Object s, Appointment a)
		{
			source = s;
			app = a;
		}
	}
}
